﻿using Autofac;
using Autofac.Core.Resolving.Pipeline;
using Autofac.Features.AttributeFilters;
using AutoRegistDependency.Interface;
using AutoRegistDependency.Utils;
using Castle.DynamicProxy;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace AutoRegistDependency.Attributes
{
    /// <summary>
    /// 配置文件值读取特性。可标记在类、属性、字段以及构造函数参数上。读取配置文件对应key的值，读取规则和原生.net core一致。
    /// Configuration file value reading feature. Can be marked on classes, properties, fields, and constructor parameters. 
    /// Read the value of the key corresponding to the configuration file, and the reading rules are consistent with the native. net core.
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
    public sealed class ValueAttribute : ParameterFilterAttribute
    {
        /// <summary>
        /// 配置文件path
        /// </summary>
        public string Path { get; }
        /// <summary>
        /// value后置处理者
        /// </summary>
        public Type ValueHandler { get;}
        /// <summary>
        /// 获取配置文件数据
        /// </summary>
        /// <param name="path">配置文件key</param>
        /// <param name="valueHandler">值处理类</param>
        public ValueAttribute(string path, Type valueHandler=null)
        {
            if (string.IsNullOrWhiteSpace(path))
            {
                throw new ArgumentException("path can not be null!");
            }
            Path = path;
            if(valueHandler != null )
            {
                if (typeof(IValueHandler).IsAssignableFrom(valueHandler))
                {
                    ValueHandler = valueHandler;
                }
                else
                {
                    throw new ArgumentException("valueHandler must be Implement IValueHandler!");
                }
            }
            
        }
        public override object ResolveParameter(ParameterInfo parameter, IComponentContext context)
        {
            IConfiguration configuration = context.Resolve<IConfiguration>();
            var configValue= configuration.GetSection(Path).Get(parameter.ParameterType);
            configValue = ExecuteValueHandler(context, configValue);
            return configValue;
        }

        public override bool CanResolveParameter(ParameterInfo parameter, IComponentContext context)
        {
            return true;
        }
        /// <summary>
        /// 执行属性value注入
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="property"></param>
        /// <param name="context"></param>
        public void ExecutePropertyValueInject(object instance, PropertyInfo property, ResolveRequestContext context)
        {
            if (instance == null) return;
            var realInstance = instance;
            if (ProxyUtil.IsProxy(instance))
            {
                realInstance = ProxyUtil.GetUnproxiedInstance(instance);
            }
            IConfiguration configuration = context.Resolve<IConfiguration>();
            object configValue = configuration.GetSection(Path).Get(property.PropertyType);
            configValue = ExecuteValueHandler(context, configValue);
            property.SetValue(realInstance, configValue);
        }
        /// <summary>
        /// 执行value字段注入
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="field"></param>
        /// <param name="context"></param>
        public void ExecuteFieldValueInject(object instance, FieldInfo field, ResolveRequestContext context)
        {
            if (instance == null) return;
            var realInstance = instance;
            if (ProxyUtil.IsProxy(instance))
            {
                realInstance = ProxyUtil.GetUnproxiedInstance(instance);
            }
            IConfiguration configuration = context.Resolve<IConfiguration>();
            object configValue = configuration.GetSection(Path).Get(field.FieldType);
            configValue = ExecuteValueHandler(context, configValue);
            field.SetValue(realInstance, configValue);
        }
        /// <summary>
        /// 执行value处理类
        /// </summary>
        /// <param name="context"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public object ExecuteValueHandler(IComponentContext context, object value)
        {
            if (ValueHandler == null)
            {
                return value;
            }
            var handler = (IValueHandler)context.Resolve(ValueHandler);
            if (handler == null)
            {
                handler = (IValueHandler)AutoFacHelper.CreateInstance(ValueHandler);
            }
            return handler.Execute(value);
        }

    }
}
